#!/usr/sbin/rsct/perl5/bin/perl 
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,2002 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# "@(#)00   1.37   src/rsct/registry/cli/bin/mksrrow.perl, srcli, rsct_rpyxh, rpyxht1f3 2/22/01 16:25:31"
######################################################################
#                                                                    #
# Module: mksrrow                                                    #
#                                                                    #
# Purpose:                                                           #
#   mksrrow - Make (add) a new row to a System Registry table.       #
#                                                                    #
# Syntax:                                                            #
#   To add rows to a table using data entered on the command line:   #
#       mksrrow [-h][-TV] Table Column=Value ... [^^...]             #
#                                                                    #
#   To add rows to a table using data predefined in an input file:   #
#       mksrrow [-h][-TV] -f Table_data_file Table                   #
#                                                                    #
# Flags:                                                             #
#   -h  Help. Writes this command's usage statement to stdout.       #
#   -f Table_data_file                                               #
#       File input. Instead of command line data, use an input file  #
#       containing row data to be added to the table.                #
#   -T  Trace. Writes this command's trace messages to stderr.       #
#   -V  Verbose. Writes this command's verbose messages to stderr.   #
#                                                                    #
# Operands:                                                          #
#   Table   The name of the table you wish to add row data to.       #
#   Column  Name of column to add data to in the new row. The name   #
#           must correspond to an existing column in the table's     #
#           metadata.                                                #
#   Value   Value to be placed in named column position in the new   #
#           row.                                                     #
#   Multiple Column=Value pairs can be specified.                    #
#   ^^      Optional. Marks the end of data for a single row, so     #
#           multiple rows can be included for addition in a single   #
#           call.                                                    #
#   Table_data_file  Input file used to provide row data.  Multiple  #
#           table definitions can be in the same input file.         #
#                                                                    #
# Description:                                                       #
#   The mksrrow command allows you to add new rows to an existing    #
#   table in the System Registry. Input is either by file (see format#
#   below) or by column_name/value pairs on the command line. If     #
#   columns are missing, the default value stored in the table       #
#   metadata is inserted.                                            #
#                                                                    #
#   The primary key column must be included in the information for   #
#   each row. A table cannot have duplicate primary key values.      #
#                                                                    #
#   When using the -f flag, the input file must contain a stanza     #
#   headed by the keyword 'RowData', using this structure:           #
#                                                                    #
#       RowData::                                                    #
#       row 1:                                                       #
#           column_name = value                                      #
#           column_name = value                                      #
#           column_name = value                                      #
#           ...                                                      #
#       row 2:                                                       #
#           column_name = value                                      #
#           ...                                                      #
#                                                                    #
#   The tab at the beginning of each line is provided here for       #
#   readability but is not necessary in the input file. Only one     #
#   table definition can be contained in the input file.             #
#                                                                    #
#   To add multiple rows on the command line, use the delimiter "^^" #
#   at the end of the data for each row.                             #
#                                                                    #
#   Using multiple row definitions is equivalent to calling the      #
#   command multiple times.                                          #
#                                                                    #
#   You must have write permission on the table you wish to add      #
#   rows to.                                                         #
#                                                                    #
#   Resource handles are entered as hexadecimal, using the format    #
#       (including quotes):                                          #
#       "0x######## 0x######## 0x######## 0x######## 0x########"     #
#   where '########' is a hexadecimal number. If more than 5         #
#   numbers are given, only the first 5 will be used. If less than   #
#   5 are given, 0x00000000 will be placed in the missing places.    #
#                                                                    #
#   Binary data is entered as hexadecimal, using the format          #
#       (including quotes):                                          #
#       "0x######## 0x######## 0x######## ..."                       #
#       -OR- "0x############..."                                     #
#   where '########' is a hexadecimal number. The length of the      #
#   hexadecimal string is not significant (each number could be      #
#   more or less than 8 digits). Values are stored as                #
#   given in the System Registry (the leading 0x is stripped off     #
#   for storage.)                                                    #
#                                                                    #
#   Long and unsigned long (64 bit) are expected in decimal format.  #
#   It is up to the caller to make sure the column value matches the #
#   data type.                                                       #
#                                                                    #
#   Strings with spaces need to be enclosed in quotes.               #
#                                                                    #
#   For more information on format for data types, please refer to   #
#   the srcli man page.                                              #
#                                                                    #
# Exit Values:                                                       #
#   0  SR_CLI_SUCCESS        Command completed successfully.         #
#   1  SR_CLI_REGISTRY_ERROR Command terminated due to an underlying #
#                            System Registry error.                  #
#   2  SR_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  SR_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   4  SR_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   5  SR_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            table to be modified.                   #
#                                                                    #
# Examples:                                                          #
#   Assumption:  Default values are used for any columns not used on #
#   the command line.                                                #
#                                                                    #
#   mksrrow -f myfile /temp/table1                                   #
#    - adds a row to the table /temp/table1 using input from the     #
#   file 'myfile' in the current directory.                          #
#                                                                    #
#   mksrrow /temp/table1 NodeNum=0 NodeName="First" Status=1         #
#    - adds the command line data to a new row in /temp/table1.      #
#                                                                    #
#   mksrrow /temp/table2 Handle="11111111 12345678 abcdefab 44444444 #
#      0000ffff" Key=10                                              #
#    - adds the command line data to a new row in /temp/table2.      #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   user input file or command line data only                        #
#                                                                    #
# Outputs:                                                           #
#   stdout - help/usage statement                                    #
#   stderr - verbose, trace and error messages                       #
#                                                                    #
# External Ref:                                                      #
#   Commands:                                                        #
#   Extensions:  CT::SR.pm CT::SRrc.pm CT::CT.pm                     #
#   Perl library routines: Getopts::Std                              #
#   SR cli library routines:                                         #
#       SR_cli_utils.pm - init_session, isRelative, term_session     #
#                printCEMsg, printCIMsg, $DEFAULT_GLOBAL_MOUNT_POINT #
#                clean_session, set_session_variables.               #
#       SR_cli_column_utils.pm - process_input_file                  #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000900 HGJ 38317: Initial delivery.                              #
#                                                                    #
######################################################################

#--------------------------------------------------------------------#
#                                                                    #
# General Program Flow/Logic:                                        #
#                                                                    #
# A: Parse command line - get table name and input file              #
# B: Initialize session with registry, including changing the        #
#    current directory if a relative path name is given (use value   #
#    given in CT_SR_HOME)                                            #
# C: Parse input file, if necessary. Create column data to be fed    #
#    into CT::SR::add_row                                            #
# D: Open file to be edited - exit if it won't open.                 #
# E: Call CT::SR::add_row                                            #
# F: Close session table and tree                                    #
#                                                                    #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# Included libraries and extensions                                  #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std;

use CT::CT qw(:ct_data_type_t);
use CT_cli_utils qw(printIMsg
                    printEMsg
);
use CT_cli_input_utils qw(  process_input_file 
                            process_cmdline_input 
);
use CT::SR;
use CT::SRrc;
use SR_cli_utils qw(init_session isRelative 
                    term_session printCEMsg 
                    printCIMsg  
                    $DEFAULT_GLOBAL_MOUNT_POINT
                    get_table_metadata  
                    free_table_metadata 
                    make_value_struct_t
                    open_table
                    clean_session
                    set_session_variables
                    error_exit
);
use SR_cli_rc qw(:return_codes);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
# Constants
$TRUE           = 1;
$FALSE          = 0;

# Variables to map globals produced by getopts
$Trace          = $FALSE;
$Verbose        = $FALSE;

$Opt_File_Input = $FALSE;

# Messaging variables
$PROGNAME       = "mksrrow";             # Program Name for messages
$MSGCAT         = "srcli.cat";           # msg catalogue for this cmd
$CTDIR          = "/usr/sbin/rsct";      # Cluster directory path
$CTBINDIR       = "$CTDIR/bin";          # Cluster Bin directory path
$LSMSG          = "$CTBINDIR/ctdspmsg";  # Display message rtn
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";   # Msg map path for $LSMSG

%Cleanup = ();                           # Hash of items to cleanup
                                         # {Session} $session to term

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
# Variables to be used with extension calls
my $Table_handle   = "";                 # init in open_table
my $Tree_handle    = "";                 # init in init_session

my $Table_name     = "";
my $Table          = "";
my $Set_work_dir   = $FALSE;
my $Command_line_input = "";
my $Column_data    = "";
my $rc             = 0;                  # assume good return code

my $Mount_point    = $DEFAULT_GLOBAL_MOUNT_POINT;


#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
# TODO: Many verbose statements in this code will eventually by
# Trace statements when the facility is available as a Perl CLI
# (feature 48401)
# TODO: security on access to the table can not be further defined
# until after a security design has been implemented for the SR.
# ( feature 48402 ) Until then, the table is opened with the
# minimum security necessary to complete the command.
# TODO: FFDC handling will be implemented in Feature 48397.


# Parse the command line, exit if there are errors
($rc, $Table_name, $filename) = parse_cmd_line();
($rc == 0) || error_exit($rc);

if ($Verbose) {
    if ($Opt_File_Input) {
        $Command_line_input = sprintf "\"  %s\n  %s\n\"", 
                        $Table_name, $filename;
    }
    else {
        my $temp_string = "";
        foreach (@ARGV) { 
            $temp = $_;
            if ($temp =~ " ") {
                $temp .= '"'.$temp.'"';
            }
            $temp_string.= "  ".$temp."\n"; 
        }
        $Command_line_input = sprintf "\"  %s\n%s\n\"", $Table_name, 
                        $temp_string;
    }
    printIMsg("IMsgmksrrowCommandLineInput", $Command_line_input);
}


# Establish registry session if possible
($Set_work_dir, $Table) = set_session_variables($Table_name);
($rc, $Tree_handle) = init_session($Set_work_dir);
($rc == 0) || error_exit($rc);

# Add the tree handle to the cleanup hash
$Cleanup{Session} = $Tree_handle;


# Open the table and quit as gracefully as possible if 
# there is an error.
($rc, $Table_handle) = 
    open_table($Tree_handle, $Table, $Table_name, SR_WRITE);
($rc == 0) || error_exit($rc);

# Add the table to the cleanup hash
push @{$Cleanup{Tables}} , $Table_handle;


# Process input depending on whether an input file was provided
# or not.
# Construct the column and field array lists to be passed 
# into CT::SR::add_row - via process_new_rows

if ($Opt_File_Input) {
    ($rc, $Column_data) = 
        process_input_file($filename, "RowData");
} 
else {  
    ($rc, $Column_data) = process_cmdline_input(\@ARGV);
}
($rc == 0) || error_exit($rc);


# Process error code from process_new_rows. Error Messages are
# handled within the subroutine.
$Trace && print STDERR "Entering process_new_rows\n";
$rc = process_new_rows($Table_handle, $Table_name, $Column_data);
$Trace && print STDERR "process_new_rows return code $rc\n";
($rc == 0) || error_exit($rc);


# Clean up after program - close table and tree for neatness
$rc = clean_session($Tree_handle, $Mount_point, $Table_handle);

# Clear the cleanup hash so clean_session isn't run again if
# there was an error from it.
%Cleanup = ();
($rc == 0) || error_exit($rc);

# Return code is 0 here
exit ($rc);


#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# process_new_rows:                                                  #
#   Parse input array to create lists of pointers to column names    #
#   and fields to be added in the new row.                           #
#   Calls sub add_row to add rows individually.                      #
#                                                                    #
# Return values:                                                     #
#   $local_rc - local return code                                    #
#   $col_array - reference to string_array_t structure holding       #
#       column names to be added in the new row.                     #
#   $fld_list - Scalar pointer to structure that handles an array    #
#       of fields to be passed into CT::SR::add_row                  #
#                                                                    #
# Global Variables altered:                                          #
#   @col_list - This may well be a legacy from using a structure     #
#       defined in an XSUB previously - this may change.             #
#   $fld_list - because Perl is sloppy in how it manages memory,     #
#       this variable had to be 'global' - using 'my' or 'local'     #
#       caused the data to be wiped out upon leaving the subroutine  #
#       to either the XSUB or the main program.                      #
#   @field - same as for $fld_list.                                  #
#                                                                    #
#--------------------------------------------------------------------#
sub process_new_rows
{

# Get input parameters
my $table = shift;
my $table_name = shift;

# Initialise variables
my $local_rc = 0;
my $badrc = 0;
my $col_type = 0;  
my $col_count = 0;
my $col_list = "";
my $name = "";
my $value = "";
my $temp = "";
my $index = 0;
my $packed_len = 0;
my $process_row = 0;

my $metadata;

($local_rc, $metadata) = get_table_metadata($table);
if ($local_rc != 0) { return $local_rc; }

my $col_defs = $metadata->getColumnDefs();

# Process the row data by row, calling sub add_row to input 
# new data to the registry.  If an unsupported data type
# information message comes up, the data is continued
# to be processed for now because it could be a resource
# handle that is being input. 

my $col_data = shift; 

foreach $row (@$col_data) {

    # The '0' here is to signal that system columns are not being
    # used here.
    my ($value_struct_t, $column_names_used);
    ($local_rc, $value_struct_t, $column_names_used) = 
        make_value_struct_t($col_defs, [], 0, $row->[1]);

    ($local_rc == 0) || return $local_rc;


    $Trace && print STDERR "Entering add_row\n";

    $local_rc = add_row($table_name, $table, 
                        $column_names_used, $value_struct_t);
    $Trace && print STDERR "add_row return code $local_rc\n";

    # Clear the memory used for the column and field lists so
    # it can be reused for the next row.

    if ($local_rc != 0) {

        # Error messages are handled within add_row
        # Continue processing if possible

        # If there has been a registry error, get out
        if ($local_rc == SR_CLI_REGISTRY_ERROR) {
            $badrc = $local_rc; 
            $count = 0;
            last;
        }

        # Save the first bad return code
        if (($local_rc != 0) && ($badrc == 0)) { 
            $badrc = $local_rc;
        }

    }

    # Set up values for next iteration
    $count--;
    $index = 0;     

    if (($local_rc != 0) || ($badrc != 0)) { last; }

} # end foreach $row (@$col_data)


$local_rc = free_table_metadata($metadata);

# Free the memory for $metadata
undef $metadata;

# Return the first bad return code that occurred 
($badrc != 0) ? return $badrc : return $local_rc;
}   # end process_new_rows


#--------------------------------------------------------------------#
# add_row:                                                           #
#   Calls SR::add_row  to add new data and checks for errors on      #
#      returning.                                                    #
#                                                                    #
# Parameters:                                                        #
#   $columns - string_array_t structure holding names to be added    #
#              and the array count                                   #
#   $fields - field_array_t structure holding fields to be added     #
#                                                                    #
# Returns:                                                           #
#   $local_rc - local return code                                    #
#--------------------------------------------------------------------#
sub add_row
{
# Grab input parameters
my $table_name = shift;
my $table_handle = shift;
my $columns = shift;
my $values = shift;

# Assume a good return code
my $local_rc = 0;

$Verbose && printIMsg("IMsgmksrrowMakingRow", $table_name);

$Trace && print "Calling CT::SR::add_row\n";
$local_rc = CT::SR::add_row($table_handle, $columns, $values );
$Trace && print "CT::SR::add_row return code: $local_rc\n";
$local_rc = error_check("sr_add_row", $local_rc, $table_name);

return $local_rc;
}   # end add_row


#--------------------------------------------------------------------#
# parse_cmd_line:                                                    #
#   Uses getopts() to grab flags on the command line, including an   #
#   input file name if the '-f' flag is used.                        #
#                                                                    #
# Paramaters:                                                        #
#   None.                                                            #
#                                                                    #
# Return values:                                                     #
#   $rc               - return code                                  #
#   $table_name       - name of table, rows being added to.          #
#   $filename         - name of file that contains column data.      #
#                                                                    #
# Global variables modified:                                         #
#   $Opt_File_Input    output   True (-f) read col data from file.   #
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#--------------------------------------------------------------------#
sub parse_cmd_line
{
my $local_rc = 0;
my $table_name = "";
my $filename = "";
my $rc = 0;
my %opts = ();

if (getopts('f:hTV', \%opts) == 0) {    # parse input flags
    printCEMsg("EMsgSRcliInvalidFlag");
    print_usage();
    return SR_CLI_BAD_FLAG;
}                   

if (defined $opts{h}) {                 # print usage and exit
    print_usage();
    exit(0);
}

$table_name = shift @ARGV;
if ((!$table_name ) || ($table_name =~ /=/)) {
    printCEMsg("EMsgSRcliNoTableName");
    print_usage(); 
    return SR_CLI_BAD_OPERAND; 
}

if (defined $opts{f}) {
    $Opt_File_Input = $TRUE;
    $filename = $opts{f};
    if ($#ARGV >= 0) {
        printCEMsg("EMsgSRcliTooManyOperands");
        print_usage();
        return SR_CLI_BAD_OPERAND;
    }
}

# Make sure if no -f flag that we have at least the key=value,
# and one more column=value specified.
if (!defined $opts{f} && $#ARGV < 1) {
    printCEMsg("EMsgSRcliNoColumnData");
    print_usage();
    return SR_CLI_BAD_OPERAND;
}

# Set Trace flag if requested
if (defined $opts{T}) {
    $Trace = $TRUE;
}

# Set Verbose flag if requested
if (defined $opts{V}) {
    $Verbose = $TRUE;
}

return ($rc, $table_name, $filename);
}   # end parse_cmd_line


#--------------------------------------------------------------------#
# error_check:                                                       #
#   Checks the return code from the SR function.  If an error is     #
#   detected appropriate error messages will be displayed and        #
#   SR CLI return code set.                                          #
#                                                                    #
# Parameters:                                                        #
#   $sr_function  - Name of the SR function that was called and      #
#                   whose error code we are checking.                #
#   $sr_rc        - SR function return code.                         #
#   $table_name   - Name of the table trying to add rows to.         #
#                                                                    #
# Return values:                                                     #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check
{
my ($sr_function, $sr_rc, $table_name) = @_;
my $rc = 0;

if ($sr_rc != 0) {
    if ($sr_rc == SR_NO_PERMISSION) {
        printEMsg("EMsgmksrrowNoPermission", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_NO_TABLE) {
        printCEMsg("EMsgSRcliNoTable", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_KEY_EXPECTED) {
        printEMsg("EMsgmksrrowNoKeyColumn", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_NO_COLUMN) {
        printEMsg("EMsgmksrrowInvalidColumn", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_DUPLICATE_KEY) {
        printEMsg("EMsgmksrrowDuplicateKey", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_CONNECTION_LOST) {
        printCEMsg("EMsgSRcliConnectionLost");
        $rc = SR_CLI_REGISTRY_ERROR;
    }
    else {
        printEMsg("EMsgmksrrowErrorMakingRow", $table_name);
        printCEMsg("EMsgSRcliSRCommandFailure", $sr_function, $sr_rc);
        $rc = SR_CLI_REGISTRY_ERROR;
    }
}

return ($rc);
}   # end error_check


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsgmksrrowUsage");
}   # end print_usage


#--------------------------------------------------------------------#
# End File                                                           #
#--------------------------------------------------------------------#
